import { EXTENSION_PATH, getExtensionConfig } from './utils';

const glob = require('glob');
const fs = require('fs');
const path = require('path');
const gulp = require('gulp');
const ts = require('gulp-typescript');
const sourcemaps = require('gulp-sourcemaps');
const rename = require('gulp-rename');
const uglify = require('gulp-uglify');
const concat = require('gulp-concat');
const clean = require('gulp-clean');
const jsobfuscator = require('gulp-javascript-obfuscator');
const debug = require('gulp-debug');
const notify = require('gulp-notify');
const merge = require('merge2');
const through = require('through2');
const yargs = require('yargs');

const econfig = getExtensionConfig();

const REG_FUNCTION = /export declare function ([_a-zA-Z0-9]+)/g;
const REG_CLASS = /export declare class ([_a-zA-Z0-9]+)/g;

/**
 * 构建包声明
 */
export function buildDeclaration(cb: () => void) {
    let argv = yargs.argv;
    let bundlePath = argv.path;

    // 检测路径是否存在
    if (!bundlePath || !fs.existsSync(bundlePath)) {
        console.error(`build declaration path '${bundlePath}' not found`);
        return cb();
    }

    // 检测是否是游戏包路径
    let pathMetaFile = bundlePath + '.meta';
    if (!fs.existsSync(pathMetaFile)) {
        console.error(`build declaration path '${bundlePath}' meta file not found`);
        return cb();
    }
    let meta = JSON.parse(fs.readFileSync(pathMetaFile, { encoding: 'utf-8' }));
    if (!meta.userData?.isBundle) {
        console.error(`build declaration path '${bundlePath}' is not bundle directory`);
        return cb();
    }

    let tsFiles = glob.sync(path.join(bundlePath, '**/*.ts'));
    console.log(tsFiles);

    let tsResult = gulp
        .src([path.join(bundlePath, '**/*.ts'), path.join(EXTENSION_PATH, 'build', '**/*.ts')])
        .pipe(
            ts.createProject(`${EXTENSION_PATH}/framework/tsconfig.json`, {
                declaration: true,
                removeComments: false,
                noEmit: false,
                composite: false
            })()
        )
        .on('error', (err: any) => {
            console.error(err.message);
        });
    return tsResult.dts
        .pipe(
            rename((path_) => {
                path_.basename = path.basename(path_.basename, '.d');
            })
        )
        .pipe(
            through.obj(function (chunk, enc, callback) {
                let sdata: string = chunk.contents.toString();
                sdata = sdata.replace(/\/\/\/ <reference types.*/g, '');
                sdata = sdata.replace(/export declare enum/g, 'export enum');
                sdata = sdata.replace(/export declare let/g, 'export let');
                sdata = sdata.replace(/export declare const/g, 'export const');

                // 找到需要定义的符号
                let symbols: string[] = [];
                for (const match of sdata.matchAll(REG_FUNCTION)) {
                    symbols.push(match[1]);
                }
                for (const match of sdata.matchAll(REG_CLASS)) {
                    symbols.push(match[1]);
                }

                // 定义列表
                let defineList: string[] = [];
                for (let symbol of symbols) {
                    sdata = sdata.replace(new RegExp(`([^_a-zA-Z0-9])${symbol}([^_a-zA-Z0-9])`, 'g'), `$1${symbol}_$2`);
                    defineList.push(`export const ${symbol}:typeof ${symbol}_ = null;`);
                }

                if (defineList.length > 0) {
                    sdata = sdata + '\n' + defineList.join('\n');
                }
                chunk.contents = Buffer.from(sdata);
                // eslint-disable-next-line @typescript-eslint/no-invalid-this
                this.push(chunk);
                callback();
            })
        )
        .pipe(gulp.dest(`${EXTENSION_PATH}/../../declarations/${path.basename(bundlePath)}`));
}

export const build = gulp.series(buildDeclaration);
